package org.teremail.message;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayDeque;
import java.util.Deque;

import org.teremail.message.builder.ContentEntityBuilder;
import org.teremail.message.builder.ContentHeadersBuilder;
import org.teremail.message.builder.EntityBuilder;
import org.teremail.message.builder.MessageHeadersBuilder;
import org.teremail.message.builder.MultipartBuilder;
import org.teremail.message.builder.MultipartEntityBuilder;
import org.teremail.message.builder.MultipartMessageBuilder;
import org.teremail.message.builder.SimpleEntityBuilder;
import org.teremail.message.builder.SimpleMessageBuilder;
import org.teremail.panto.BodyHeader;
import org.teremail.panto.ContentHandler;
import org.teremail.store.Store;
import org.teremail.util.IO;

public class FooContentHandler implements ContentHandler {

    private final Deque<EntityBuilder> builderStack = 
        new ArrayDeque<EntityBuilder>();
    private EntityBuilder lastBuilder;
    private final Store store;
    private boolean isMessage = false;
    private MessageHeadersBuilder headers = null;
    private ContentHeadersBuilder contentHeaders = new ContentHeadersBuilder();
    
    public FooContentHandler(Store store) {
        this.store = store;
    }

    public void body(BodyHeader header, InputStream is) throws IOException {
        
        
        if (isMessage) {
            assert headers != null;
            
            SimpleMessageBuilder smb = new SimpleMessageBuilder(contentHeaders.build(), headers, null);
            builderStack.push(smb);
            isMessage = false;
            headers = null;
        } else {
            assert contentHeaders != null;
            
            builderStack.push(new SimpleEntityBuilder(contentHeaders));
        }
        
        ContentEntityBuilder b = (ContentEntityBuilder) builderStack.peek();
        
        String id = store.createStoreItem();
        OutputStream out = store.getOutputStream(id);
        IO.copy(is, out);
        out.flush();
        out.close();
        b.setContent(new Content(id));
        popAndAddToLast();
    }
    
    private void popAndAddToLast() {
        lastBuilder = builderStack.pop();
        if (builderStack.size() > 0) {
            MultipartBuilder mb = (MultipartBuilder) builderStack.peek();
            mb.addEntityBuilder(lastBuilder);
        }
    }

    public void endBodyPart() {
    }

    public void endHeader() {
    }

    public void endMessage() {
    }

    public void endMultipart() {
        popAndAddToLast();
    }

    public void epilogue(InputStream in) throws IOException {
        MultipartBuilder mb = (MultipartBuilder) builderStack.peek();
        String epilogue = IO.toString(in, Charset.forName("US-ASCII"));
        mb.setEpilogue(epilogue);
    }

    public void field(String fieldData) {
        if (isMessage) {
            headers.add(fieldData);
        } else {
            contentHeaders.add(fieldData);
        }
    }

    public void preamble(InputStream in) throws IOException {
        MultipartBuilder mb = (MultipartBuilder) builderStack.peek();
        String preamble = IO.toString(in, Charset.forName("US-ASCII"));
        mb.setPreamble(preamble);
    }

    public void startBodyPart() {
    }

    public void startHeader() {
        if (isMessage) {
            headers = new MessageHeadersBuilder();
        } else {
            contentHeaders = new ContentHeadersBuilder();
        }
    }

    public void startMessage() {
        isMessage = true;
    }

    public void startMultipart(BodyHeader header) {
        if (isMessage) {
            builderStack.push(new MultipartMessageBuilder(headers, contentHeaders));
            isMessage = false;
        } else {
            builderStack.push(new MultipartEntityBuilder(contentHeaders));
        }
    }

    public Message getMessage() {
        return (Message) lastBuilder.build();
    }

}
